<!-- 表单项动态渲染父组件传递的 formConfig，用 title 作为标签文字 -->
<template>
  <template v-for="item in formConfig" :key="item.dataIndex">
    <!-- 分割线 -->
    <a-divider
      v-if="item.type === 'separator' && !toValue(item.hidden)"
      orientation="left"
      style="color: #1677ff; font-weight: normal"
    >
      <span>{{ item.title }}</span>
    </a-divider>

    <a-form-item
      :label="item.title"
      :name="parentName ? [...parentName, item.dataIndex] : item.dataIndex"
      :validateStatus="validateInfos[item.dataIndex]?.validateStatus"
      :help="getFormItemHelp(item)"
      v-else-if="!toValue(item.hidden)"
    >
      <!-- 树形选择器：自动生成 placeholder -->
      <a-tree-select
        v-if="item.type === 'tree-select'"
        v-model:value="formData[item.dataIndex]"
        showSearch
        allowClear
        treeDefaultExpandAll
        :placeholder="getPlaceholder(item)"
        :treeData="item.treeData"
      />

      <!-- 输入框：自动生成 placeholder -->
      <a-input
        v-else-if="item.type === 'input'"
        v-model:value.trim="formData[item.dataIndex]"
        :maxlength="item.maxlength"
        :placeholder="getPlaceholder(item)"
        v-bind="item.props"
      />

      <!-- 多行输入框：自动生成 placeholder -->
      <a-textarea
        v-else-if="item.type === 'textarea'"
        v-model:value.trim="formData[item.dataIndex]"
        :maxlength="item.maxlength"
        :placeholder="getPlaceholder(item)"
        showCount
        v-bind="item.props"
      />

      <!-- 图标选择器：自动生成 placeholder -->
      <div v-else-if="item.type === 'icon-select'">
        <IconSelect @updateIcon="(icon: any) => (formData[item.dataIndex] = icon)">
          <template #iconSelect>
            <a-row :gutter="20" align="middle">
              <a-col flex="1">
                <a-input
                  autocomplete="off"
                  v-model:value="formData[item.dataIndex]"
                  :placeholder="getPlaceholder(item)"
                  v-bind="item.props"
                />
              </a-col>
              <a-col v-if="($antIcons as any)[formData[item.dataIndex]]">
                <component :is="($antIcons as any)[formData[item.dataIndex]]" style="font-size: 20px" />
              </a-col>
            </a-row>
          </template>
        </IconSelect>
      </div>

      <!-- 开关：无需 placeholder -->
      <a-switch v-else-if="item.type === 'switch'" v-model:checked="formData[item.dataIndex]" v-bind="item.props" />

      <!-- 数字输入框：自动生成 placeholder -->
      <a-input-number
        v-else-if="item.type === 'input-number'"
        v-model:value="formData[item.dataIndex]"
        :placeholder="getPlaceholder(item)"
        v-bind="item.props"
        style="width: 100%"
      />

      <!-- 选择器：自动生成 placeholder -->
      <a-select
        v-else-if="item.type === 'select'"
        v-model:value="formData[item.dataIndex]"
        :placeholder="getPlaceholder(item)"
        allowClear
        showSearch
        v-bind="item.props"
        :options="toValue(item.props?.options)"
      />
      <!-- 多选选择器：自动生成 placeholder -->
      <a-select
        v-else-if="item.type === 'multiple-select'"
        v-model:value="formData[item.dataIndex]"
        mode="multiple"
        :placeholder="getPlaceholder(item)"
        allowClear
        v-bind="item.props"
        :options="toValue(item.props?.options)"
      />

      <!-- 多选 -->
      <a-checkbox-group
        v-else-if="item.type === 'checkbox'"
        :name="item.dataIndex"
        v-model:value="formData[item.dataIndex]"
        v-bind="item.props"
        :options="toValue(item.props?.options)"
      />

      <!-- 单选 -->
      <a-radio-group
        v-else-if="item.type === 'radio'"
        :name="item.dataIndex"
        v-model:value="formData[item.dataIndex]"
        v-bind="item.props"
        :options="toValue(item.props?.options)"
      />

      <!-- 级联选择器 -->
      <a-cascader
        v-else-if="item.type === 'cascader'"
        v-model:value="formData[item.dataIndex]"
        :placeholder="getPlaceholder(item)"
        :showSearch="{ filter: cascaderFilter }"
        v-bind="item.props"
        :options="toValue(item.props?.options)"
      />

      <!-- 上传 -->
      <PictureCardUpload
        v-else-if="item.type === 'upload'"
        v-model:fileList="formData[item.dataIndex]"
        :beforeUpload="(file: any) => onBeforeUpload(file, item.uploadMaxSize)"
        v-bind="item.props"
      />

      <!-- 日期选择器 -->
      <FormatDatePicker v-else-if="item.type === 'date-picker'" v-model:value="formData[item.dataIndex]" v-bind="item.props" />
      <!-- 日期范围选择器 -->
      <FormatRangePicker v-else-if="item.type === 'range-picker'" v-model:value="formData[item.dataIndex]" v-bind="item.props" />
      <!-- 长期 或 日期选择器 -->
      <CheckboxDatePicker
        v-else-if="item.type === 'checkbox-date-picker'"
        v-model:value="formData[item.dataIndex]"
        v-bind="item.props"
      />
    </a-form-item>
  </template>
</template>
<script setup lang="ts">
  import { computed, ref, toValue } from 'vue';
  import { FileUtil } from '@/utils/utils';
  import type { ShowSearchType } from 'ant-design-vue/es/cascader';
  import IconSelect from '@/components/common/select/icon-select.vue';
  import type { ValidateInfo } from 'ant-design-vue/es/form/useForm';
  import type { UploadFile } from 'ant-design-vue';
  import PictureCardUpload from '@/components/common/upload/picture-card-upload.vue';
  import FormatDatePicker from '@/components/common/date-picker/format-date-picker.vue';
  import FormatRangePicker from '@/components/common/date-picker/format-range-picker.vue';
  import CheckboxDatePicker from '@/components/template/date-picker/checkbox-date-picker-template.vue';
  import { cloneDeep, isFunction, isNumber, isString } from 'lodash-es';
  import { bizApi } from '@/api/biz';

  // ========================== 1. 类型定义 ==========================
  /** 表单项配置类型 */
  export interface FormItemTemplateConfig {
    title: string; // 标签文字
    dataIndex: string; // 绑定的表单字段名
    // 组件类型
    type:
      | 'input'
      | 'textarea'
      | 'switch'
      | 'input-number'
      | 'tree-select'
      | 'icon-select'
      | 'select'
      | 'multiple-select'
      | 'checkbox'
      | 'radio'
      | 'cascader'
      | 'upload'
      | 'range-picker'
      | 'date-picker'
      | 'checkbox-date-picker'
      | 'separator';
    maxlength?: number; // 输入框最大长度（仅 input 类型）
    props?: Record<string, any>; // 组件额外属性（如 switch 的 checkedChildren）
    treeData?: any[]; // 树形选择器自定义树数据
    hidden?: boolean | ((value?: any) => boolean); // 是否隐藏（默认 false）
    uploadMaxSize?: number; // 上传文件大小限制（仅 upload 类型）
    isFormConfigMap?: boolean; // 是否经过组件内映射处理
  }
  export interface FormItemTemplateProps {
    formData: Record<string, any>;
    formConfig: FormItemTemplateConfig[];
    validateInfos?: Record<string, ValidateInfo>;
    parentName?: string[];
  }

  /** 组件接收的 Props */
  const props = withDefaults(defineProps<FormItemTemplateProps>(), {
    validateInfos: () => ({}),
  });

  // 表单配置
  const formConfig = computed(() => {
    return formConfigMap(cloneDeep(props.formConfig));
  });

  function formConfigMap(formConfig: FormItemTemplateConfig[]): FormItemTemplateConfig[] {
    return formConfig.map((item) => {
      const config = item;
      // 0.已经映射过的 config 不再处理
      if (config.isFormConfigMap) {
        return config;
      }
      config.isFormConfigMap = true;
      // 1.处理 options 属性，允许通过 action 进行远程查询
      if (config.props?.options && !Array.isArray(config.props.options)) {
        const { action, params } = getActionAndParams(config.props!.options);
        config.props.options = () => {
          if (optionsMap.value[action]) {
            return optionsMap.value[action];
          } else {
            getOptionsDataInfo(action, params);
          }
          return [];
        };
      }
      // 2.处理 hidden 属性，允许每次 formData 发生变化时重新计算
      if (isFunction(config.hidden)) {
        config.hidden = config.hidden.bind(null, props.formData);
      }
      // 3.处理 upload 组件默认的上传大小限制，未配置的情况下默认5MB
      if (config.type === 'upload' && config.uploadMaxSize === undefined) {
        config.uploadMaxSize = 5;
      }
      // 4.处理 textarea 组件默认的行数限制
      if (config.type === 'textarea') {
        const defaultRows = config.props?.maxRows && config.props.maxRows < 3 ? config.props.maxRows : 3;
        config.props = {
          autoSize: { minRows: config.props?.minRows ?? defaultRows, maxRows: config.props?.maxRows ?? defaultRows },
          ...config.props,
        };
      }
      return config as any;
    });
  }

  /**
   * 遵循modal-form-template的动态表单使用规则
   * 从 value 中获取 action 与 params
   */
  function getActionAndParams(value: string | { action: string; params?: Record<string, any> }) {
    const action = isString(value) ? value : value.action;
    const params = isString(value) ? {} : value.params || {};

    return { action, params };
  }

  function getFormItemHelp({ dataIndex, type, uploadMaxSize, title, props: InputProps }: FormItemTemplateConfig) {
    const help = props.validateInfos[dataIndex]?.help;
    // 优先使用 validateInfos 中的 help 信息
    if (help) {
      return help;
    }

    if (type === 'upload') {
      let help = undefined;
      if (isNumber(uploadMaxSize) && uploadMaxSize > 0) {
        help = `${help || ''}${title}大小不能超过 ${uploadMaxSize} MB；`;
      }
      if (InputProps?.accept) {
        help = `${help || ''}允许的文件类型为 ${InputProps.accept}；`;
      }
      return help;
    }
    return undefined;
  }

  /* ----------------------- 表单中数据输入组件使用的工具函数 ------------------------ */

  // 表单中所有options数据与action对应
  const optionsMap = ref<Record<string, any[]>>({});
  // 表单中所有options中的loading状态
  const optionsLoadingMap = ref<Record<string, boolean>>({});

  function onBeforeUpload(file: UploadFile, uploadMaxSize?: number) {
    if (isNumber(uploadMaxSize) && uploadMaxSize > 0) {
      return FileUtil.isLtNum(file, uploadMaxSize);
    }

    return true;
  }

  /* 通过请求动态获取选择器的options数据 */
  async function getOptionsDataInfo(action: string, params: any) {
    if (optionsLoadingMap.value[action]) {
      return;
    }
    optionsLoadingMap.value[action] = true;
    const result = await bizApi.httpList(action, params);
    // console.log(`optionsMap.value[${action}]`, result);
    optionsMap.value[action] = result;
    optionsLoadingMap.value[action] = false;
  }

  // 级联选择器支持搜索功能
  const cascaderFilter: ShowSearchType['filter'] = (_inputValue, path) => {
    const inputValue = _inputValue.toLowerCase();
    return path.some((option) => option.label.toLowerCase().includes(inputValue));
  };

  /**
   * 自动生成占位符：根据组件类型匹配固定前缀
   * - 选择类组件（select）：前缀“请选择”
   * - 输入类组件（input）：前缀“请输入”
   */
  function getPlaceholder(item: FormItemTemplateConfig) {
    const selectTypeList: FormItemTemplateConfig['type'][] = ['tree-select', 'select', 'multiple-select', 'cascader']; // 选择类组件
    const inputTypeList: FormItemTemplateConfig['type'][] = ['input', 'input-number', 'icon-select', 'textarea']; // 输入类组件

    if (selectTypeList.includes(item.type)) {
      return `请选择${item.title}`; // 选择类：请选择XX（如“请选择上级模块”）
    } else if (inputTypeList.includes(item.type)) {
      return `请输入${item.title}`; // 输入类：请输入XX（如“请输入模块名称”）
    }
    return undefined; // 开关等组件无需 placeholder
  }
</script>
<style lang="less" scoped></style>
